package org.example.utils.market.Kind;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.example.dao.dao.market.CKindDao;
import org.example.dao.dto.market.CKindDto;
import org.example.dao.entity.market.CKind;
import org.example.dao.entity.market.CStore;
import org.example.exception.ServerErrorException;
import org.example.skytool.commom.IdWorker;
import org.example.skytool.commom.StringUtil;
import org.example.skytool.json.JackSonUtil;
import org.example.skytool.redis.CacheClient;
import org.example.skytool.redis.RedisUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

import static org.example.skytool.redis.RedisConstants.*;

/**
 * @author xluo
 * @date 2023/11/9 8:19
 */
@Component
public class RedisKindService {

    @Resource
    private RedisUtils redisUtils;

    @Resource
    private CacheClient cacheClient;

    @Resource
    private IdWorker idWorker;

    @Resource
    private CKindDao cKindDao;

    public String getKindVersionKey(String storeId, String fatherId) {
        return MARKET_MOUDLE + MARKET_KIND_CONTROLLER + MARKET_KIND_IDS_KIND +
                MARKET_KIND_STORE_KIND + storeId + MARKET_KIND_FATHER_KIND + fatherId + MARKET_KIND_VERSION_KIND;
    }

    public String getKindIdsKey(String storeId, String fatherId, String version){
        return MARKET_MOUDLE + MARKET_KIND_CONTROLLER + MARKET_KIND_IDS_KIND +
                MARKET_KIND_STORE_KIND + storeId + MARKET_KIND_FATHER_KIND + fatherId + MARKET_KIND_TOTAL_KIND + version;
    }

    public String getKindContentKey(String kindId) {
        return MARKET_MOUDLE + MARKET_KIND_CONTROLLER + MARKET_KIND_CACHE_KIND + kindId;
    }

    public String getKindContentLock(String kindId) {
        return MARKET_MOUDLE + MARKET_KIND_CONTROLLER + MARKET_KIND_CACHE_KIND + kindId + ":lock";
    }

    /**
     * 构建kind缓存
     */
    public void setKindIdsCache(Long storeId, Long fatherId) {
        String version = redisUtils.stringGet(getKindVersionKey(storeId == null ? "0" : String.valueOf(storeId),
                String.valueOf(fatherId)));
        String newVersion = idWorker.nextId() + "";
        Long start = 1L;
        Long limit = 50L;
        Long count = 0L;
        do {
            List<String> result = new ArrayList<>();
            List<CKindDto> kinds = cKindDao.getKinds(storeId, fatherId, start, limit);
            count = (long) kinds.size();
            start ++;
            if (count != 0) {
                for (CKindDto kind : kinds) {
                    result.add(String.valueOf(kind.getId()));
                }
                redisUtils.listRightAddAll(getKindIdsKey(String.valueOf(storeId), String.valueOf(fatherId), newVersion),
                        result.toArray(new String[0]));
            }
        } while (limit.equals(count));
        redisUtils.stringSet(getKindVersionKey(String.valueOf(storeId), String.valueOf(fatherId)), newVersion);
        //删除旧缓存
        if (!StringUtil.isEmpty(version)) {
            redisUtils.del(getKindIdsKey(String.valueOf(storeId), String.valueOf(fatherId), version));
        }
    }

    /**
     * 获取类型信息
     */
    public IPage<CKindDto> getKindsCache(Long storeId, Long fatherId, Integer limit, Integer start) {
        String version = redisUtils.stringGet(getKindVersionKey(String.valueOf(storeId), String.valueOf(fatherId)));
        if (version == null) {
            throw new ServerErrorException("market kind ids version不存在");
        }
        List<String> ids = redisUtils.listGet(getKindIdsKey(String.valueOf(storeId), String.valueOf(fatherId), version),
                start - 1, limit);
        List<CKindDto> cacheStoresContent = getCacheKindsContent(ids);
        IPage<CKindDto> result = new Page<>(start, limit);
        result.setRecords(cacheStoresContent);
        result.setTotal(redisUtils.listGetSize(getKindIdsKey(String.valueOf(storeId), String.valueOf(fatherId), version)));
        return result;
    }

    /**
     * 批量获取类型信息
     */
    public List<CKindDto> getCacheKindsContent(List<String> kindIds) {
        if (kindIds == null) {
            return null;
        }
        List<String> kindKeys = new ArrayList<>();
        for (String kindId : kindIds) {
            kindKeys.add(getKindContentKey(kindId));
        }
        List<String> kinds = redisUtils.stringMutiGet(kindKeys);
        List<CKindDto> results = new ArrayList<>();
        for (int i = 0; i < kinds.size(); i++) {
            CKindDto kindDto;
            if (kinds.get(i) == null || Objects.equals(kinds.get(i), "")) {
                kindDto = getCacheKindContent(kindIds.get(i));
            } else {
                kindDto = JackSonUtil.parse(CKindDto.class, kindIds.get(i));
            }
            results.add(kindDto);
        }
        return results;
    }

    /**
     * 获取单个类型信息
     */
    public CKindDto getCacheKindContent(String kindId) {

        String cacheKey = getKindContentKey(kindId);
        Class<CKindDto> type = CKindDto.class;
        Map<String, Object> param = new HashMap<>();
        param.put("id", kindId);
        String lockKey = getKindContentLock(kindId);

        Function<Map, CKindDto> dbFallback = params -> {
            Long id = Long.valueOf((String) params.get("id"));
            CKindDto cStore = cKindDao.getKindDto(id);
            return cStore;
        };

        Long time = 30L;
        TimeUnit unit = TimeUnit.MINUTES;
        Long nullTtl = 30L;

        CKindDto result = cacheClient.queryString(cacheKey, type, param, lockKey, dbFallback, time, unit, nullTtl);

        return result;
    }

}
